package org.bet.web.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.bet.utils.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import org.springframework.web.servlet.view.JsonView;

public class GeneModelTrackActionController extends MultiActionController {
	protected static final Logger logger = Logger.getLogger(GeneModelTrackActionController.class);
	
	private GeneModelService geneModelService = null;
 
	public GeneModelService getGeneModelService() {
		return geneModelService;
	}

	public void setGeneModelService(GeneModelService geneModelService) {
		this.geneModelService = geneModelService;
	}

	// Methods for handling actions, including syndicate, range, lookup
	public ModelAndView syndicate(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logger.debug("Enter syndicate...");
		
		logger.debug("Request parameters:" + ServletRequestUtils.getRequestParameterAsString(request, ","));

		Map<String, Object> model = new HashMap<String, Object>();
		model.put("success", true);
//		model.put("data", geneModelService.getSyndicator());
		
		return new ModelAndView(new JsonView(), model);
	}
	
	


	public ModelAndView range(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logger.debug("Enter range...");
		logger.debug("Request parameters:" + ServletRequestUtils.getRequestParameterAsString(request, ","));	

		Properties params = new Properties();
		
		params.put("assemblyId", ServletRequestUtils.getStringParameter(request, "assembly"));
		params.put("start", ServletRequestUtils.getStringParameter(request, "left"));
		params.put("end", ServletRequestUtils.getStringParameter(request, "right"));
		
		
		List<GeneModel> geneModelList = geneModelService.findGeneModelList(params);
		
		Object[] dataArray = new Object[geneModelList == null? 0 : geneModelList.size()];
		
		int geneCount = 0;
		if(geneModelList != null){
			for(int i = 0; i < dataArray.length; i++){
				GeneModel gm = geneModelList.get(i);
				
				dataArray[i] = new Object[]{ 
						(gm.getParent() == null)? null : gm.getParent().getId(),  
						gm.getId(),
						gm.getStrand(), 
						gm.getFeature().name(), 
						gm.getRange().getStart(), 
						gm.getRange().length()
					};
				
				if(gm.getParent() == null){
					geneCount++;
				}
			}
		}
		
		Map<String, Object> model = new HashMap<String, Object>();
		model.put("success", true);
		model.put("message", "Found " + geneCount + " gene models");
		model.put("data", dataArray);

//		model.put("data", new Object[]{
//				new Object[]{null,"AT1G01010.1","+","mRNA",3631,2269},
//				new Object[]{"AT1G01010.1","f3","+","five_prime_UTR",3631,129},
//				new Object[]{"AT1G01010.1","f6","+","CDS",3760,154},
//				new Object[]{"AT1G01010.1","f7","+","CDS",3996,281},
//				new Object[]{"AT1G01010.1","f9","+","CDS",4486,120},
//				new Object[]{"AT1G01010.1","f11","+","CDS",4706,390},
//				new Object[]{"AT1G01010.1","f13","+","CDS",5174,153},
//				new Object[]{"AT1G01010.1","f15","+","CDS",5439,192},
//				new Object[]{"AT1G01010.1","f17","+","three_prime_UTR",5631,269},
//				new Object[]{null,"AT1G01030.1","-","mRNA",11649,2066},
//				new Object[]{"AT1G01030.1","f240756","-","three_prime_UTR",11649,215},
//				new Object[]{"AT1G01030.1","f240755","-","CDS",11864,1077},
//				new Object[]{"AT1G01030.1","f240754","-","five_prime_UTR",12941,233},
//				new Object[]{"AT1G01030.1","f240752","-","five_prime_UTR",13335,380},
//		});

		return new ModelAndView(new JsonView(), model);		
	}

	public ModelAndView lookup(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logger.debug("Enter range...");
		logger.debug("Request parameters:" + ServletRequestUtils.getRequestParameterAsString(request, ","));	

		Properties params = new Properties();
		
		params.put("keywords", ServletRequestUtils.getStringParameter(request, "query", ""));
		params.put("firstResult", ServletRequestUtils.getStringParameter(request, "start", "0"));
		params.put("maxResults", ServletRequestUtils.getStringParameter(request, "limit", "10"));
		
		// TODO: This approach very slow, any ather nice solution to find the total count?
		long totalCount = geneModelService.getGeneModelCount(params);
		
		List<GeneModel> geneModelList = geneModelService.findGeneModelList(params);
		int nResult = CollectionUtils.size(geneModelList);
		
		Map<String, Object> model = new HashMap<String, Object>();
		model.put("success", true);
		model.put("count", totalCount);
		
		LookupResult[] resultArray = new LookupResult[nResult];
		
		for(int i = 0; i < nResult; i++){
			GeneModel gm = geneModelList.get(i);			
			resultArray[i] = new LookupResult(gm.getId(), gm.getAssembly().getId(), gm.getRange().getStart(), gm.getRange().getEnd(), gm.getDescription());
		}
		
		model.put("rows", resultArray);
		
		return new ModelAndView(new JsonView(), model);		
		
	}

	public class LookupResult{
		String id;
		String assembly;
		long start;
		long end;
		String description;
		
		public LookupResult(){}
		
		public LookupResult(String id, String assembly, long start, long end, String description) {
			this.id = id;
			this.assembly = assembly;
			this.start = start;
			this.end = end;
			this.description = description;
		}

		public String getId() {
			return id;
		}

		public void setId(String id) {
			this.id = id;
		}

		public String getAssembly() {
			return assembly;
		}

		public void setAssembly(String assembly) {
			this.assembly = assembly;
		}

		public long getStart() {
			return start;
		}

		public void setStart(long start) {
			this.start = start;
		}

		public long getEnd() {
			return end;
		}

		public void setEnd(long end) {
			this.end = end;
		}

		public String getDescription() {
			return description;
		}

		public void setDescription(String description) {
			this.description = description;
		}
		
	}
}

